/**
 * @Author: Nick Zhang <thesadboy@vip.qq.com>
 * @Description: 注释工具类
 * @Date: 2024-06-18 13:14:25
 * @LastEditors: Nick Zhang <thesadboy@vip.qq.com>
 * @LastEditTime: 2024-10-11 15:45:39
 */
package com.nickzhang.jetbrains.file_description_plugin.utils

import com.intellij.openapi.editor.Document
import com.intellij.openapi.vfs.VirtualFile
import com.nickzhang.jetbrains.file_description_plugin.configs.AppSettingState
import kotlinx.serialization.json.jsonObject
import java.io.BufferedReader
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.*

class CommentUtil {
    companion object {
        /**
         * 执行命令
         */
        private fun executeCommand(command: String): String? {
            return try {
                val processBuilder = ProcessBuilder(command.trim().split(" "))
                processBuilder.redirectErrorStream(true)
                val process = processBuilder.start()
                val reader = BufferedReader(InputStreamReader(process.inputStream))
                val output = reader.readLine()
                reader.close()
                process.waitFor()
                output ?: null
            } catch (e: Exception) {
                null
            }
        }

        /**
         * 获取用户名和邮箱
         */
        private fun getUserInfo(command: String): String {
            if (!command.startsWith("git")) return command
            var cmd = command
            if (cmd.matches(Regex("git config user.name\\s+git config user.email"))) {
                cmd = "git config user.name && git config user.email"
            }
            return cmd.split("&&").mapNotNull { executeCommand(it) }.joinToString(" ")
        }

        private fun getCommentStartInsertPosition(fileExt: String, content: String): Int {
            val startString = when (fileExt.lowercase()) {
                "php" -> "<?php\n"
                else -> ""
            }
            return content.indexOf(startString) + startString.length
        }

        /**
         * 获取注释开始的标志
         */
        private fun getCommentStart(fileExt: String): String? {
            return when (fileExt.lowercase()) {
                "javascript", "php" -> if (AppSettingState.getInstance().compactComment) "/*\n" else "/**\n"
                "html" -> "<!--\n"
                "property" -> "###\n"
                "python" -> "\"\"\"\n"
                "dart" -> ""
                else -> null
            }
        }

        /**
         * 获取注释结束的标志
         */
        private fun getCommentEnd(fileExt: String): String? {
            return when (fileExt.lowercase()) {
                "javascript", "php" -> " */\n"
                "html" -> " -->\n"
                "property" -> "###\n"
                "python" -> "\"\"\"\n"
                "dart" -> ""
                else -> null
            }
        }

        /**
         * 获取每行注释开始的标志
         */
        private fun getCommentLineStart(fileExt: String, isReg: Boolean = false): String {
            return when (fileExt.lowercase()) {
                "javascript", "html", "php" -> {
                    if (isReg) {
                        " \\* "
                    } else {
                        " * "
                    }
                }

                "dart" -> "/// "

                "property" -> " # "
                else -> ""
            }
        }

        /**
         * 获取@符号
         */
        private fun getAtSymbol(fileExt: String): String {
            return when (fileExt.lowercase()) {
                "python" -> ""
                else -> "@"
            }
        }


        private fun commentContentReplace(content: String): String {
            var res = content
            val user = executeCommand("git config user.name") ?: ""
            val email = executeCommand("git config user.email") ?: ""
            val map: Map<String, String> = mapOf(
                "\${now_year}" to SimpleDateFormat("yyyy").format(Date()),
                "\${git_name}" to user,
                "\${git_email}" to email,
                "\${git_name_email}" to "$user $email"
            )
            for (entry in map) {
                res = res.replace(entry.key, entry.value)
            }
            return res
        }

        /**
         * 更新头部注释
         */
        fun updateCommentHeader(document: Document, file: VirtualFile) {
            var content = document.text
            val fileExt = CommonUtil.getFileExtension(file)
            // 检查是否需要替换头部注释内容
            if (generateHeaderCommentReg(file).find(content) == null) {
                return
            }
            val headerCommentConfig = CommonUtil.getHeaderCommentConfig()
            val lastEditorsKey = "LastEditors"
            val lastEditTimeKey = "LastEditTime"
            val filePathKey = "FilePath"
            val curDate = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
            val filePath = CommonUtil.getRelativePath(file)
            val at = getAtSymbol(fileExt)
            // 在找出的匹配项中，替换@LastEditors和@LastEditTime
            content = content.replace(generateHeaderCommentReg(file)) { matchResult: MatchResult ->
                var res = matchResult.groupValues[0]
                if (headerCommentConfig.jsonObject.containsKey(lastEditorsKey)) {
                    val user = getUserInfo(headerCommentConfig.jsonObject[lastEditorsKey].toString().trim('"'))
                    res = res.replace(
                        (getCommentLineStart(fileExt, true) + "$at$lastEditorsKey:[^\\n]*\n").toRegex(),
                        getCommentLineStart(fileExt) + "$at$lastEditorsKey: $user\n"
                    )
                }
                res = res.replace(
                    (getCommentLineStart(fileExt, true) + "$at$lastEditTimeKey:[^\\n]*\n").toRegex(),
                    getCommentLineStart(fileExt) + "$at$lastEditTimeKey: $curDate\n"
                )
                res.replace(
                    (getCommentLineStart(fileExt, true) + "$at$filePathKey:[^\\n]*\n").toRegex(),
                    getCommentLineStart(fileExt) + "$at$filePathKey: $filePath\n"
                )
            }
            CommonUtil.saveFileContent(file, document, content)
        }

        /**
         * 检查并添加头部注释
         */
        fun checkAddCommentHeader(document: Document, file: VirtualFile) {
            val content = document.text
            // 检查是否需要添加请求头
            if (generateHeaderCommentReg(file).find(content) != null) {
                return
            }
            val updatedHeader = generateHeaderComment(file)
            if (updatedHeader !== "") {
                val position = getCommentStartInsertPosition(CommonUtil.getFileExtension(file), content)
                val cStart = content.substring(0, position)
                val cEnd = content.substring(position)
                CommonUtil.saveFileContent(file, document, "$cStart$updatedHeader$cEnd")
            }
        }

        /**
         * 生成头部注释判定正则
         */
        private fun generateHeaderCommentReg(file: VirtualFile): Regex {
            val fileExt = CommonUtil.getFileExtension(file)
            val headerCommentConfig = CommonUtil.getHeaderCommentConfig()
            val at = getAtSymbol(fileExt)
            val commentStartWithReg = getCommentStart(fileExt)?.replace("\n", "\\n")?.replace("*", "\\*")
            val commentEndWithReg = getCommentEnd(fileExt)?.replace("\n", "\\n")?.replace("*", "\\*")
            val noKeyStr = "((?!($commentStartWithReg|$commentEndWithReg))[\\w\\W]*)?"
            var commentContent = ""
            for (entry in headerCommentConfig.jsonObject) {
                val key = entry.key
                val value = entry.value.toString().trim('"')
                if (key.firstOrNull()?.isUpperCase() == true) {
                    commentContent += getCommentLineStart(fileExt, true) + "$at$key:[^\\n]*\\n"
                    commentContent += noKeyStr
                } else {
                    if (value != "") {
                        commentContent += getCommentLineStart(fileExt, true) + "[^\\n]*\\n"
                        commentContent += noKeyStr
                    }
                }
            }
            return commentContent.toRegex()
        }

        /**
         * 生成头部注释
         */
        private fun generateHeaderComment(file: VirtualFile): String {
            val fileExt = CommonUtil.getFileExtension(file)
            var commentContent = ""
            val headerCommentConfig = CommonUtil.getHeaderCommentConfig()
            val curDate = SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Date())
            val createDate = CommonUtil.getFileCreationTime(file)
            val filePath = CommonUtil.getRelativePath(file)
            val at = getAtSymbol(fileExt)
            if (getCommentStart(fileExt) !== null) {
                for (entry in headerCommentConfig.jsonObject) {
                    val key = entry.key
                    val value = entry.value.toString().trim('"')
                    when (key) {
                        "Author" -> {
                            commentContent += getCommentLineStart(fileExt) + "$at$key: ${getUserInfo(value)}\n"
                        }

                        "Date" -> {
                            commentContent += getCommentLineStart(fileExt) + "$at$key: $createDate\n"
                        }

                        "LastEditors" -> {
                            commentContent += getCommentLineStart(fileExt) + "$at$key: ${getUserInfo(value)}\n"
                        }

                        "LastEditTime" -> {
                            commentContent += getCommentLineStart(fileExt) + "$at$key: $curDate\n"
                        }

                        "FilePath" -> {
                            commentContent += getCommentLineStart(fileExt) + "$at$key: $filePath\n"
                        }

                        else -> {
                            if (key.firstOrNull()?.isUpperCase() == true) {
                                commentContent += getCommentLineStart(fileExt) + "$at$key: $value\n"
                            } else {
                                if (value != "") {
                                    commentContent += getCommentLineStart(fileExt) + "$value\n"
                                }
                            }
                        }
                    }
                }
            }
            if (commentContent === "") return ""
            return getCommentStart(fileExt) + commentContentReplace(commentContent) + getCommentEnd(fileExt)
        }

        /**
         * 插入娱乐注释
         */
        fun insertFunComment(document: Document, file: VirtualFile, comment: String) {
            val fileExt = CommonUtil.getFileExtension(file)
            val content = document.text
            val funCommentInHeaderComment = AppSettingState.getInstance().funCommentInHeaderComment
            val funComment: String = comment.replace("//", getCommentLineStart(fileExt))
            var headerComment = ""
            content.replace(generateHeaderCommentReg(file)) { matchResult: MatchResult ->
                headerComment = matchResult.groupValues[0]
                matchResult.groupValues[0]
            }
            var res = ""
            if (funCommentInHeaderComment && headerComment !== "") {
                val contents = content.split(headerComment)
                val before = contents[0]
                val after = contents[1]
                res = "$before$funComment$headerComment$after"
            } else {
                if (getCommentStart(fileExt) !== null) {
                    val position = getCommentStartInsertPosition(fileExt, content)
                    val cStart = content.substring(0, position)
                    val cEnd = content.substring(position)
                    res = "$cStart${getCommentStart(fileExt)}$funComment${getCommentEnd(fileExt)}$cEnd"
                }
            }
            if (res !== "") {
                CommonUtil.saveFileContent(file, document, res)
            }
        }
    }
}
